-----------------------------------------------
-- Project		: ECE 251 FINAL PROJECT
-- Author 		: Mahmut Yilmaz
-- Last Modified: 04/12/2007
-----------------------------------------------

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE work.all;

ENTITY lfsr8 IS
	PORT (	clock			: IN  STD_LOGIC;	-- PosEdge Clock used	
			reset			: IN  STD_LOGIC;	-- Resets all flops to 0, active HIGH
      		q	 			: OUT STD_LOGIC_VECTOR(7 DOWNTO 0); -- output pseudo-random number
			polynomial		: IN  STD_LOGIC_VECTOR(7 DOWNTO 0); -- set LFSR polynomial
																 -- it is recommended to set shift_enable='0'
																 -- before changing the polynomial
			seed 			: IN  STD_LOGIC_VECTOR(7 DOWNTO 0); -- seed to LFSR
																 -- it is recommended to set shift_enable='0'
																 -- before changing the polynomial
			seed_change		: IN  STD_LOGIC;	-- Enable seed change. Resets all flops first.
			shift_enable	: IN  STD_LOGIC 	-- Enable shift & pseudo-random number generation, active HIGH
			);
END lfsr8;

ARCHITECTURE struct OF lfsr8 IS
	COMPONENT one_bit_block 
		PORT (	xor_in0			: IN  STD_LOGIC;	-- XOR input from feedback line	
				mux_sel			: IN  STD_LOGIC;	-- Multiplexer select
				flop_in			: IN  STD_LOGIC;	-- D flop input
				flop_clock		: IN  STD_LOGIC;	-- PosEdge Clock used	
				flop_reset		: IN  STD_LOGIC;	-- Resets the flop to 0, active HIGH
				flop_set		: IN  STD_LOGIC;	-- Sets the flop to 1, active HIGH
				lfsr_out		: OUT STD_LOGIC; 	-- Output as an LFSR output bit
	      		output_next		: OUT STD_LOGIC 	-- Output: input to next stage
				);
	END COMPONENT;
	
	COMPONENT dflop IS
		PORT (	clock			: IN  STD_LOGIC;	-- PosEdge Clock used	
				reset			: IN  STD_LOGIC;	-- Resets the flop to 0, active HIGH
				set				: IN  STD_LOGIC;	-- Sets the flop to 1, active HIGH
				input			: IN  STD_LOGIC;	-- Flop input
	      		q	 			: OUT STD_LOGIC 	-- Flop output
				);	
	END COMPONENT;
	
	COMPONENT g_and2 IS
		PORT (	in0,in1			: IN  STD_LOGIC;	-- AND inputs	
	      		q	 			: OUT STD_LOGIC 	-- AND output
				);
	END COMPONENT;
	
	COMPONENT g_and3 IS
		PORT (	in0,in1,in2		: IN  STD_LOGIC;	-- AND inputs	
	      		q	 			: OUT STD_LOGIC 	-- AND output
				);
	END COMPONENT;

	COMPONENT g_xor2 IS
		PORT (	in0,in1			: IN  STD_LOGIC;	-- XOR inputs	
	      		q	 			: OUT STD_LOGIC 	-- XOR output
				);
	END COMPONENT;
	
	COMPONENT g_inv IS
		PORT (	in0 			: IN  STD_LOGIC;	-- INV input
	      		q	 			: OUT STD_LOGIC 	-- INV output
				);
	END COMPONENT;
	
	SIGNAL inter_states : STD_LOGIC_VECTOR(7 DOWNTO 0);
	SIGNAL seed_enabled : STD_LOGIC_VECTOR(7 DOWNTO 0);
	SIGNAL clock_enabled: STD_LOGIC;
	SIGNAL seed_change_inverted: STD_LOGIC;
BEGIN
	-- Invert seed_change
	seed_change_inverted <= NOT seed_change;
	-- Create an enabled clock
	-- No clock toggling if shift_enable is '0' or seed_change is high
	clock_enabled <= shift_enable AND clock AND seed_change_inverted;
	-- Generate enabled seeds
	seed_enabled(0) <= seed_change AND seed(0);
	seed_enabled(1) <= seed_change AND seed(1);
	seed_enabled(2) <= seed_change AND seed(2);
	seed_enabled(3) <= seed_change AND seed(3);
	seed_enabled(4) <= seed_change AND seed(4);
	seed_enabled(5) <= seed_change AND seed(5);
	seed_enabled(6) <= seed_change AND seed(6);
	seed_enabled(7) <= seed_change AND seed(7);

	-- one_bit_block group
	bit_block_0: one_bit_block PORT MAP ( xor_in0=>inter_states(7),mux_sel=>polynomial(0),
		flop_in=>inter_states(7),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(0),lfsr_out=>q(0),output_next=>inter_states(0));
	bit_block_1:  one_bit_block PORT MAP ( xor_in0=>inter_states(7),mux_sel=>polynomial(1),
		flop_in=>inter_states(0),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(1),lfsr_out=>q(1),output_next=>inter_states(1));
	bit_block_2:  one_bit_block PORT MAP ( xor_in0=>inter_states(7),mux_sel=>polynomial(2),
		flop_in=>inter_states(1),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(2),lfsr_out=>q(2),output_next=>inter_states(2));
	bit_block_3:  one_bit_block PORT MAP ( xor_in0=>inter_states(7),mux_sel=>polynomial(3),
		flop_in=>inter_states(2),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(3),lfsr_out=>q(3),output_next=>inter_states(3));
	bit_block_4:  one_bit_block PORT MAP ( xor_in0=>inter_states(7),mux_sel=>polynomial(4),
		flop_in=>inter_states(3),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(4),lfsr_out=>q(4),output_next=>inter_states(4));
	bit_block_5:  one_bit_block PORT MAP ( xor_in0=>inter_states(7),mux_sel=>polynomial(5),
		flop_in=>inter_states(4),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(5),lfsr_out=>q(5),output_next=>inter_states(5));
	bit_block_6:  one_bit_block PORT MAP ( xor_in0=>inter_states(7),mux_sel=>polynomial(6),
		flop_in=>inter_states(5),flop_clock=>clock_enabled,flop_reset=>reset,
		flop_set=>seed_enabled(6),lfsr_out=>q(6),output_next=>inter_states(6));
	
	-- the last flop
	last_flop: dflop PORT MAP (clock=>clock_enabled,reset=>reset,set=>seed_enabled(7),
		input=>inter_states(6),q=>inter_states(7));	
	
	q(7) <= inter_states(7);
	
END struct;


